# -*- coding: utf-8 -*-
"""
系统配置管理服务

提供系统配置的读取、写入、验证、缓存等核心功能
按照模块文档-09-系统管理.md的2.2节规范实现
"""

import json
import hashlib
from typing import Dict, List, Optional, Any, Union
from datetime import datetime
from sqlalchemy.orm import Session
from sqlalchemy import and_, or_

from ..models.system_config import (
    SystemConfig, 
    SystemConfigHistory, 
    SystemConfigTemplate,
    ConfigCategory, 
    ConfigType, 
    ConfigScope,
    DEFAULT_SYSTEM_CONFIGS
)
from ..core.database import get_db
from ..core.security import encrypt_sensitive_data, decrypt_sensitive_data
from ..core.cache import cache_manager
from ..core.exceptions import ValidationError, NotFoundError, BusinessError


class SystemConfigService:
    """系统配置管理服务类"""

    def __init__(self, db: Session):
        self.db = db
        self.cache_prefix = "system_config:"
        self.cache_expiry = 3600  # 1小时缓存

    def get_config(self, key: str, default: Any = None, use_cache: bool = True) -> Any:
        """
        获取单个配置值
        
        Args:
            key: 配置键
            default: 默认值
            use_cache: 是否使用缓存
            
        Returns:
            配置值，如果不存在则返回默认值
        """
        # 尝试从缓存获取
        if use_cache:
            cache_key = f"{self.cache_prefix}{key}"
            cached_value = cache_manager.get(cache_key)
            if cached_value is not None:
                return cached_value

        # 从数据库获取
        config = self.db.query(SystemConfig).filter(
            and_(
                SystemConfig.config_key == key,
                SystemConfig.is_active == True
            )
        ).first()

        if not config:
            return default

        # 解析配置值
        value = self._parse_config_value(config)
        
        # 缓存结果
        if use_cache:
            cache_manager.set(cache_key, value, self.cache_expiry)

        return value

    def get_configs_by_category(self, category: ConfigCategory, use_cache: bool = True) -> Dict[str, Any]:
        """
        获取指定分类的所有配置
        
        Args:
            category: 配置分类
            use_cache: 是否使用缓存
            
        Returns:
            配置字典 {key: value}
        """
        cache_key = f"{self.cache_prefix}category:{category.value}"
        
        # 尝试从缓存获取
        if use_cache:
            cached_configs = cache_manager.get(cache_key)
            if cached_configs is not None:
                return cached_configs

        # 从数据库获取
        configs = self.db.query(SystemConfig).filter(
            and_(
                SystemConfig.config_category == category,
                SystemConfig.is_active == True
            )
        ).order_by(SystemConfig.sort_order, SystemConfig.config_key).all()

        result = {}
        for config in configs:
            result[config.config_key] = self._parse_config_value(config)

        # 缓存结果
        if use_cache:
            cache_manager.set(cache_key, result, self.cache_expiry)

        return result

    def get_configs_by_group(self, group_name: str, category: Optional[ConfigCategory] = None) -> List[Dict[str, Any]]:
        """
        获取指定分组的配置项（用于前端表单显示）
        
        Args:
            group_name: 分组名称
            category: 配置分类（可选）
            
        Returns:
            配置项列表，包含完整的配置信息
        """
        query = self.db.query(SystemConfig).filter(
            and_(
                SystemConfig.group_name == group_name,
                SystemConfig.is_active == True
            )
        )
        
        if category:
            query = query.filter(SystemConfig.config_category == category)
            
        configs = query.order_by(SystemConfig.sort_order, SystemConfig.config_key).all()

        result = []
        for config in configs:
            config_dict = {
                "id": config.id,
                "config_key": config.config_key,
                "config_value": config.config_value if not config.is_encrypted else "***",
                "config_category": config.config_category,
                "config_type": config.config_type,
                "display_name": config.display_name,
                "description": config.description,
                "default_value": config.default_value,
                "validation_rule": config.validation_rule,
                "options": config.options,
                "is_required": config.is_required,
                "is_readonly": config.is_readonly,
                "is_sensitive": config.is_sensitive,
                "group_name": config.group_name,
                "sort_order": config.sort_order
            }
            result.append(config_dict)

        return result

    def set_config(self, key: str, value: Any, operator: str, reason: str = None, 
                   client_ip: str = None, user_agent: str = None) -> bool:
        """
        设置配置值
        
        Args:
            key: 配置键
            value: 配置值
            operator: 操作人
            reason: 变更原因
            client_ip: 客户端IP
            user_agent: 用户代理
            
        Returns:
            是否设置成功
            
        Raises:
            ValidationError: 配置值验证失败
            NotFoundError: 配置项不存在
        """
        # 查找配置项
        config = self.db.query(SystemConfig).filter(SystemConfig.config_key == key).first()
        if not config:
            raise NotFoundError(f"配置项 {key} 不存在")

        # 检查是否只读
        if config.is_readonly:
            raise BusinessError(f"配置项 {key} 为只读，不允许修改")

        # 验证配置值
        if not config.validate_value(value):
            raise ValidationError(f"配置值验证失败: {key} = {value}")

        # 记录旧值
        old_value = config.config_value

        # 转换和加密配置值
        new_value = self._serialize_config_value(config, value)
        
        # 更新配置
        config.config_value = new_value
        config.last_modified_by = operator
        config.last_modified_at = datetime.utcnow()

        # 记录变更历史
        history = SystemConfigHistory(
            config_id=config.id,
            config_key=key,
            old_value=old_value,
            new_value=new_value,
            change_type="update",
            change_reason=reason,
            operated_by=operator,
            operated_at=datetime.utcnow(),
            client_ip=client_ip,
            user_agent=user_agent
        )
        self.db.add(history)

        try:
            self.db.commit()
            
            # 清除缓存
            self._clear_config_cache(key, config.config_category)
            
            return True
        except Exception as e:
            self.db.rollback()
            raise BusinessError(f"保存配置失败: {str(e)}")

    def batch_set_configs(self, configs: Dict[str, Any], operator: str, 
                         reason: str = None, client_ip: str = None, user_agent: str = None) -> Dict[str, bool]:
        """
        批量设置配置
        
        Args:
            configs: 配置字典 {key: value}
            operator: 操作人
            reason: 变更原因
            client_ip: 客户端IP
            user_agent: 用户代理
            
        Returns:
            设置结果 {key: success}
        """
        results = {}
        
        for key, value in configs.items():
            try:
                success = self.set_config(key, value, operator, reason, client_ip, user_agent)
                results[key] = success
            except Exception as e:
                results[key] = False
                # 记录错误日志
                print(f"批量设置配置失败: {key} = {value}, 错误: {str(e)}")

        return results

    def get_config_history(self, key: str, limit: int = 50) -> List[Dict[str, Any]]:
        """
        获取配置变更历史
        
        Args:
            key: 配置键
            limit: 返回记录数限制
            
        Returns:
            历史记录列表
        """
        histories = self.db.query(SystemConfigHistory).filter(
            SystemConfigHistory.config_key == key
        ).order_by(SystemConfigHistory.operated_at.desc()).limit(limit).all()

        result = []
        for history in histories:
            result.append({
                "id": history.id,
                "old_value": history.old_value,
                "new_value": history.new_value,
                "change_type": history.change_type,
                "change_reason": history.change_reason,
                "operated_by": history.operated_by,
                "operated_at": history.operated_at.isoformat(),
                "client_ip": history.client_ip
            })

        return result

    def export_configs(self, category: Optional[ConfigCategory] = None, 
                      include_sensitive: bool = False) -> Dict[str, Any]:
        """
        导出配置
        
        Args:
            category: 配置分类（可选）
            include_sensitive: 是否包含敏感配置
            
        Returns:
            配置导出数据
        """
        query = self.db.query(SystemConfig).filter(SystemConfig.is_active == True)
        
        if category:
            query = query.filter(SystemConfig.config_category == category)
            
        if not include_sensitive:
            query = query.filter(SystemConfig.is_sensitive == False)

        configs = query.order_by(SystemConfig.config_category, SystemConfig.sort_order).all()

        export_data = {
            "export_time": datetime.utcnow().isoformat(),
            "version": "2.0.0",
            "category": category.value if category else "all",
            "include_sensitive": include_sensitive,
            "configs": []
        }

        for config in configs:
            config_data = {
                "config_key": config.config_key,
                "config_value": config.config_value,
                "config_category": config.config_category.value,
                "config_type": config.config_type.value,
                "display_name": config.display_name,
                "description": config.description,
                "default_value": config.default_value,
                "validation_rule": config.validation_rule,
                "options": config.options,
                "is_required": config.is_required,
                "is_readonly": config.is_readonly,
                "is_sensitive": config.is_sensitive,
                "group_name": config.group_name,
                "sort_order": config.sort_order
            }
            export_data["configs"].append(config_data)

        return export_data

    def import_configs(self, import_data: Dict[str, Any], operator: str, 
                      overwrite: bool = False) -> Dict[str, Any]:
        """
        导入配置
        
        Args:
            import_data: 导入数据
            operator: 操作人
            overwrite: 是否覆盖现有配置
            
        Returns:
            导入结果统计
        """
        if "configs" not in import_data:
            raise ValidationError("无效的导入数据格式")

        success_count = 0
        fail_count = 0
        skip_count = 0
        errors = []

        for config_data in import_data["configs"]:
            try:
                key = config_data["config_key"]
                existing_config = self.db.query(SystemConfig).filter(
                    SystemConfig.config_key == key
                ).first()

                if existing_config and not overwrite:
                    skip_count += 1
                    continue

                if existing_config:
                    # 更新现有配置
                    for field, value in config_data.items():
                        if field != "config_key" and hasattr(existing_config, field):
                            setattr(existing_config, field, value)
                    existing_config.last_modified_by = operator
                    existing_config.last_modified_at = datetime.utcnow()
                else:
                    # 创建新配置
                    new_config = SystemConfig(**config_data)
                    new_config.created_by = operator
                    new_config.updated_by = operator
                    self.db.add(new_config)

                success_count += 1

            except Exception as e:
                fail_count += 1
                errors.append(f"{config_data.get('config_key', 'unknown')}: {str(e)}")

        try:
            self.db.commit()
            # 清除所有配置缓存
            self._clear_all_config_cache()
        except Exception as e:
            self.db.rollback()
            raise BusinessError(f"导入配置失败: {str(e)}")

        return {
            "success_count": success_count,
            "fail_count": fail_count,
            "skip_count": skip_count,
            "errors": errors
        }

    def initialize_default_configs(self, operator: str = "system") -> bool:
        """
        初始化默认配置
        
        Args:
            operator: 操作人
            
        Returns:
            是否初始化成功
        """
        try:
            for config_data in DEFAULT_SYSTEM_CONFIGS:
                existing = self.db.query(SystemConfig).filter(
                    SystemConfig.config_key == config_data["config_key"]
                ).first()

                if not existing:
                    config = SystemConfig(**config_data)
                    config.created_by = operator
                    config.updated_by = operator
                    self.db.add(config)

            self.db.commit()
            return True
        except Exception as e:
            self.db.rollback()
            raise BusinessError(f"初始化默认配置失败: {str(e)}")

    def get_all_groups(self, category: Optional[ConfigCategory] = None) -> List[Dict[str, Any]]:
        """
        获取所有配置分组信息
        
        Args:
            category: 配置分类（可选）
            
        Returns:
            分组信息列表
        """
        query = self.db.query(
            SystemConfig.group_name,
            SystemConfig.config_category
        ).filter(
            and_(
                SystemConfig.is_active == True,
                SystemConfig.group_name.isnot(None)
            )
        ).distinct()

        if category:
            query = query.filter(SystemConfig.config_category == category)

        groups = query.all()
        
        result = []
        for group_name, config_category in groups:
            # 统计分组内配置数量
            count = self.db.query(SystemConfig).filter(
                and_(
                    SystemConfig.group_name == group_name,
                    SystemConfig.config_category == config_category,
                    SystemConfig.is_active == True
                )
            ).count()

            result.append({
                "group_name": group_name,
                "category": config_category.value,
                "config_count": count
            })

        return result

    def _parse_config_value(self, config: SystemConfig) -> Any:
        """解析配置值"""
        if config.is_encrypted and config.config_value:
            # 解密敏感数据
            try:
                decrypted_value = decrypt_sensitive_data(config.config_value)
                return decrypted_value
            except Exception:
                return config.default_value
        
        return config.parsed_value

    def _serialize_config_value(self, config: SystemConfig, value: Any) -> str:
        """序列化配置值"""
        if config.config_type == ConfigType.JSON:
            serialized = json.dumps(value, ensure_ascii=False)
        elif config.config_type == ConfigType.BOOLEAN:
            serialized = "true" if value else "false"
        else:
            serialized = str(value)

        # 加密敏感数据
        if config.is_encrypted:
            try:
                return encrypt_sensitive_data(serialized)
            except Exception:
                return serialized

        return serialized

    def _clear_config_cache(self, key: str, category: ConfigCategory):
        """清除指定配置的缓存"""
        cache_manager.delete(f"{self.cache_prefix}{key}")
        cache_manager.delete(f"{self.cache_prefix}category:{category.value}")

    def _clear_all_config_cache(self):
        """清除所有配置缓存"""
        cache_manager.delete_pattern(f"{self.cache_prefix}*")

    def test_config_connection(self, config_type: str, config_data: Dict[str, Any]) -> Dict[str, Any]:
        """
        测试配置连接（如数据库、邮件服务器等）
        
        Args:
            config_type: 配置类型（database/email/sms等）
            config_data: 配置数据
            
        Returns:
            测试结果
        """
        try:
            if config_type == "email":
                return self._test_email_connection(config_data)
            elif config_type == "database":
                return self._test_database_connection(config_data)
            elif config_type == "sms":
                return self._test_sms_connection(config_data)
            else:
                return {"success": False, "message": f"不支持的配置类型: {config_type}"}
        except Exception as e:
            return {"success": False, "message": f"测试连接失败: {str(e)}"}

    def _test_email_connection(self, config_data: Dict[str, Any]) -> Dict[str, Any]:
        """测试邮件服务器连接"""
        import smtplib
        from email.mime.text import MIMEText
        
        try:
            server = smtplib.SMTP(config_data["smtp_server"], config_data["smtp_port"])
            server.starttls()
            server.login(config_data["smtp_username"], config_data["smtp_password"])
            server.quit()
            return {"success": True, "message": "邮件服务器连接成功"}
        except Exception as e:
            return {"success": False, "message": f"邮件服务器连接失败: {str(e)}"}

    def _test_database_connection(self, config_data: Dict[str, Any]) -> Dict[str, Any]:
        """测试数据库连接"""
        # 这里可以根据需要实现数据库连接测试
        return {"success": True, "message": "数据库连接测试功能待实现"}

    def _test_sms_connection(self, config_data: Dict[str, Any]) -> Dict[str, Any]:
        """测试短信服务连接"""
        # 这里可以根据需要实现短信服务连接测试
        return {"success": True, "message": "短信服务连接测试功能待实现"}